/** * Copyright 2017 LinkedIn Corp. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ package com.github.ambry.store; import com.github.ambry.utils.TestUtils; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import org.junit.Test; import static org.junit.Assert.*; /** * Unit tests {@link CostBenefitInfo} */ public class CostBenefitInfoTest { /** * Tests {@link CostBenefitInfo} for construction and getters */ @Test public void testCostBenefitInfo() { for (int i = 0; i < 5; i++) { List<String> randomSegments = CompactionPolicyTest.generateRandomStrings(3); long cost = getRandomCost(); int benefit = 1 + TestUtils.RANDOM.nextInt(Integer.MAX_VALUE); CostBenefitInfo actual = new CostBenefitInfo(randomSegments, cost, benefit); verifyCostBenfitInfo(actual, randomSegments, cost, benefit, cost * (1.0 / benefit)); } } /** * Tests {@link CostBenefitInfo} for 0 benefit */ @Test public void testCostBenefitInfoForZeroBenefit() { List<String> randomSegments = CompactionPolicyTest.generateRandomStrings(3); long cost = getRandomCost(); int benefit = 0; CostBenefitInfo actual = new CostBenefitInfo(randomSegments, cost, benefit); verifyCostBenfitInfo(actual, randomSegments, cost, benefit, Double.MAX_VALUE); } /** * Tests {@link CostBenefitInfo} for comparisons */ @Test public void testCostBenefitInfoComparison() { List<String> randomSegments = CompactionPolicyTest.generateRandomStrings(3); long cost = getRandomCost(); int benefit = 1 + TestUtils.RANDOM.nextInt(Integer.MAX_VALUE - 1); CostBenefitInfo one = new CostBenefitInfo(randomSegments, cost, benefit); // generate a CostBenefitInfo with cost = 1 + one's cost compareAndTest(one, 1, 0, -1); // generate a CostBenefitInfo with cost = 1 - one's cost compareAndTest(one, -1, 0, 1); // generate a CostBenefitInfo with same cost as one compareAndTest(one, 0, 0, 0); // generate a CostBenefitInfo with benefit = 1 + one's benefit compareAndTest(one, 0, 1, 1); // generate a CostBenefitInfo with benefit = 1 - one's benefit compareAndTest(one, 0, -1, -1); // test a case where costBenefitRatio is same, but diff cost and benefit. cost = ThreadLocalRandom.current().nextLong(Integer.MAX_VALUE / 2); benefit = 2 + TestUtils.RANDOM.nextInt(Integer.MAX_VALUE / 2 - 2); if (cost % 2 != 0) { cost++; } if (benefit % 2 != 0) { benefit++; } one = new CostBenefitInfo(randomSegments, cost, benefit); // generate a CostBenefitInfo with cost = half of one and benefit = half of one. CostBenefit is same, but one'e // benefit is more compareAndTest(one, (cost / 2) * (-1), (benefit / 2) * (-1), -1); } /** * Generate random cost greater than {@link Integer#MAX_VALUE} * @return randomly generated cost */ private long getRandomCost() { long cost = ThreadLocalRandom.current().nextLong(Integer.MAX_VALUE); if (cost < Integer.MAX_VALUE) { cost += Integer.MAX_VALUE; } return cost; } /** * Compares the {@code actual} {@link CostBenefitInfo} with a new one that is generated based on the arguments passed * @param actual Actual {@link CostBenefitInfo} to be compared against * @param costDiff cost difference to generate the new {@link CostBenefitInfo} wrt {@code actual} * @param benefitDiff benefit difference to generate the new {@link CostBenefitInfo} wrt {@code actual} * @param comparisonValue expected comparison value */ private void compareAndTest(CostBenefitInfo actual, long costDiff, int benefitDiff, int comparisonValue) { CostBenefitInfo newCostBenefitInfo = new CostBenefitInfo(actual.getSegmentsToCompact(), actual.getCost() + costDiff, actual.getBenefit() + benefitDiff); assertTrue("Cost Benefit info comparison mismatch ", actual.compareTo(newCostBenefitInfo) == comparisonValue); assertTrue("Cost Benefit info comparison mismatch ", newCostBenefitInfo.compareTo(actual) == comparisonValue * -1); } /** * Verifies {@link CostBenefitInfo} for expected values * @param actual {@link CostBenefitInfo} to be compared against * @param segmentNames expected segment names of this candidate * @param cost expected cost * @param benefit expected benefit * @param costBenefitRatio expected cost benefit ratio */ private void verifyCostBenfitInfo(CostBenefitInfo actual, List<String> segmentNames, long cost, int benefit, double costBenefitRatio) { assertEquals("Log segment names mismatch ", segmentNames, actual.getSegmentsToCompact()); assertEquals("Cost mismatch ", cost, actual.getCost()); assertEquals("Benefit mismatch ", benefit, actual.getBenefit()); assertTrue("CostBenefitRatio mismatch ", actual.getCostBenefitRatio().compareTo(costBenefitRatio) == 0); } }